{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:05.731287Z",
     "start_time": "2025-01-23T12:00:05.723285Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 准备数据",
   "id": "8d5488202f3a7bd8"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.594991Z",
     "start_time": "2025-01-23T12:00:05.899325Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from tensorflow import keras\n",
    "\n",
    "# 用karas有的数据集imdb，电影分类,分电影是积极的，还是消极的\n",
    "imdb = keras.datasets.imdb\n",
    "\n",
    "# 载入数据使用下面两个参数\n",
    "# 词典大小，仅保留训练数据中前10000个最经常出现的单词，低频单词被舍弃\n",
    "# 前一万个词出现词频最高的会保留下来进行处理，后面的作为特殊字符处理，\n",
    "vocab_size = 10000\n",
    "index_from = 3  # 0,1,2,3空出来做别的事\n",
    "# 小于3的id都是特殊字符\n",
    "# 需要注意的一点是取出来的词表还是从1开始的，需要做处理\n",
    "\n",
    "# 下载数据集，并将数据集分为训练集和测试集\n",
    "(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=vocab_size, index_from=index_from)\n",
    "# train_data和test_data的类型都是列表的列表\n",
    "# 每个列表代表对应文本中每个单词的id值所组成的列表，只记录出现频率最高的前10000个单词\n",
    "# train_labels和test_labels的类型都是numpy.ndarray类型列表,是二分类"
   ],
   "id": "99e15a8bf4ac2398",
   "outputs": [],
   "execution_count": 25
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.601992Z",
     "start_time": "2025-01-23T12:00:09.596992Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(type(train_data))  # <class 'numpy.ndarray'>\n",
    "print(type(train_labels))  # <class 'numpy.ndarray'>\n",
    "print(\"-\" * 50)\n",
    "\n",
    "print(type(test_data))  # <class 'numpy.ndarray'>\n",
    "print(type(test_labels))  # <class 'numpy.ndarray'>"
   ],
   "id": "91baa1e0a4bcff51",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n",
      "<class 'numpy.ndarray'>\n",
      "--------------------------------------------------\n",
      "<class 'numpy.ndarray'>\n",
      "<class 'numpy.ndarray'>\n"
     ]
    }
   ],
   "execution_count": 26
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.609561Z",
     "start_time": "2025-01-23T12:00:09.603993Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(train_data.shape)  # (25000,)\n",
    "print(train_labels.shape)  # (25000,)\n",
    "print(\"-\" * 50)\n",
    "\n",
    "print(test_data.shape)  # (25000,)\n",
    "print(test_labels.shape)  # (25000,)"
   ],
   "id": "c73ae5103250c21a",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(25000,)\n",
      "(25000,)\n",
      "--------------------------------------------------\n",
      "(25000,)\n",
      "(25000,)\n"
     ]
    }
   ],
   "execution_count": 27
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.616959Z",
     "start_time": "2025-01-23T12:00:09.611559Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(type(train_data[0]))  # <class 'list'>\n",
    "print(type(train_labels[0]))  # <class 'numpy.int64'>"
   ],
   "id": "4c0b6e4c4236628",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'list'>\n",
      "<class 'numpy.int64'>\n"
     ]
    }
   ],
   "execution_count": 28
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.623704Z",
     "start_time": "2025-01-23T12:00:09.617957Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(train_data[0])\n",
    "print(\"-\" * 50)\n",
    "\n",
    "print(train_labels[0:10])"
   ],
   "id": "aa0d8cec6373bf38",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]\n",
      "--------------------------------------------------\n",
      "[1 0 0 1 0 0 1 0 1 0]\n"
     ]
    }
   ],
   "execution_count": 29
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.702177Z",
     "start_time": "2025-01-23T12:00:09.625646Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 载入词表，看下词表长度，词表就像英语字典\n",
    "word_index = imdb.get_word_index()\n",
    "print(len(word_index))\n",
    "print(type(word_index))"
   ],
   "id": "ba986276e2fb2d8c",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88584\n",
      "<class 'dict'>\n"
     ]
    }
   ],
   "execution_count": 30
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 构造 word2idx 和 idx2word",
   "id": "efa6a9ce868c9b65"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.736181Z",
     "start_time": "2025-01-23T12:00:09.703174Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 0,1,2,3空出来做别的事,这里的idx是从1开始的,所以加3\n",
    "word2idx = {word: idx + 3 for word, idx in word_index.items()}\n",
    "\n",
    "word2idx.update({\n",
    "    \"[PAD]\": 0,  # 填充 token\n",
    "    \"[BOS]\": 1,  # begin of sentence，句子开始\n",
    "    \"[UNK]\": 2,  # 未知 token\n",
    "    \"[EOS]\": 3  # end of sentence，句子结束\n",
    "})\n",
    "\n",
    "# # 反向词典,id变为单词\n",
    "idx2word = {idx: word for word, idx in word2idx.items()}"
   ],
   "id": "270bc30c8df50599",
   "outputs": [],
   "execution_count": 31
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.741203Z",
     "start_time": "2025-01-23T12:00:09.737182Z"
    }
   },
   "cell_type": "code",
   "source": "print(word2idx[\"hello\"])",
   "id": "2be77f4c5e107070",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4825\n"
     ]
    }
   ],
   "execution_count": 32
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:09.745910Z",
     "start_time": "2025-01-23T12:00:09.742183Z"
    }
   },
   "cell_type": "code",
   "source": "print(idx2word[4825])",
   "id": "d0d2953c7bfa08f8",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello\n"
     ]
    }
   ],
   "execution_count": 33
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.626107Z",
     "start_time": "2025-01-23T12:00:09.748907Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 获取 max_length\n",
    "length_collect = {}\n",
    "\n",
    "#统计样本中每个长度出现的次数\n",
    "for text in train_data:\n",
    "    length = len(text)  # 句子长度\n",
    "    # 如果 length 已经存在于 length_collect 字典中，则将其对应的值加 1。\n",
    "    # 如果 length 不存在于 length_collect 字典中，则将其添加到字典中，并将其值初始化为 1。\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1  # 统计每个长度出现的次数\n",
    "\n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())  # 画出每个长度出现的次数的柱状图\n",
    "# axvline():用于在图表中绘制一条垂直于 x 轴的直线。第一个参数是指定直线的位置。\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "\n",
    "plt.legend()\n",
    "plt.show()"
   ],
   "id": "3425a418cd0677a5",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 34
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.791789Z",
     "start_time": "2025-01-23T12:00:10.627619Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 相对句子长度画个直方图，看看长度分布\n",
    "length_list = [len(text) for text in train_data]\n",
    "plt.hist(length_list, bins=50)\n",
    "plt.xlabel(\"length\")\n",
    "plt.ylabel(\"frequency\")\n",
    "plt.axvline(500, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ],
   "id": "83e8b75c0824ebbe",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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wJr0tNts9erVdjNr2bKle4xGobp429KlS+25Puobx3nDKA1yEhMTZePGje4xwedwjnHOcbalHvQcwRuyJu3j135n3YL7+wF4n34o1i04k7HewPW11GMKw3HshUj9IU3PGfya8z20xUR99NFHFrzpOCJtFNCeD20hCu7KUho8/Pzzz1avLVu2pKtOR44ckbp169q5gzc9X6dOnc5Zd6eeFysjz302UTPKVCNZXaBPB2o5qxfrG06b0oJp8KP7nGOCgyFnv7PvXMdokKORtQ72Sk37hrVJElmf/iP7+9//7pYBICvT8Tw6vujhhx92XwtutXFo44I2GGjgpN1v2jCgPSRpUadOHes203G5BQsWvKB66mBvHc/7448/WnCltNXpzz//PCPwiZaUKFHTQqTdYzfffLOUKVMmKppZtcvO2XS0PbImberWvmndmHYPIKvTcUWrVq2ycbDaYvPkk0+mGIzsdKlpL4iOq9UxRjobTB9TtyKdTefOnW0ck84s00HVOhZXxw49+uijsnv37jSdQ3t0NAjT2W46YFwDIy1rI0Rwy5p2jenYIG28SB0sZbaouEPogC8dB6QDwBx6A9NfnrYaBdNZZrrPOSb1rDPn+fmO0ag3VOuQ0tlouj94AwAg0rTFWycXdejQwQYr64Dr4NYiHcyss63HjRsnZcuWtde0/Pvvv1vwlBb58uWTb775xoao6PfSliVtadIxROm5H7733nvWI9OsWTObWq8tVTouSAeOO3R8r06o0rpee+21EkkxgSgYWKEDoN98801riXG6NbRlRgddT5kyxabbO4O0NOrUyFcHxelAMR3ZrjPUtGlP6bQ+fTNo/6kGNjrAWqdXOgO9lPaBHjhwQGbPnp2m+mn3muZB0DpFc3CUlmn1O0a3ET/Rpljnd6/Nxxfazw8gOulNWlswdPJM8I0W0Wf37t0W+GgDSIsWLTLlPZCe+3fEB1XoICmdPdatW7cUYzz0B9CINC4uzpJC6Q+is4QaNWpkwZDS/AyahVin440ZM8aa3HT6ouYu0mBI9erVy0bZDx482PpUFyxYYNMTZ80iJ49fAiLNxaH0vUJABACZY8GCBTZAWz+MasOF3oe1i0xbjKJRxAMijRR16mCohFE6NV7HfWgLkc780tlh2vTn0JubJmzSRFYaKOXPn98Cq5EjR7rHaMSowY/mNNJkWprQSnMhMOXeH/T9o33uThkAkDmSk5MtaeS2bdusq0wHg2vSyGhNfxIVXWbRji4zAIhOdJkhKUxdZnxkBgBkeXy2969AmH73BEQAgCzL6X4JXq8M/nLi/9IJXOwY0YiPIQIyug9bl29xBthHa981gAujN0FN4Oss66BTxoPz3MDbTp8+bYvs6u/9YpPvEhDB802pmmLBKQPwHifvXEavdYXopBNmNGfSxQbCBETwNP3EoOv8OGUA3qM3Ql38U/PRaasw/CVXrlxhmUXMHQK++OQAwB/dZ+Qaw4ViUDUAAPA9Wojg+QF3P/30k5V1PR6SMwIAQuHuAE87efKkfPLJJ7ZpGQCAUGghgucHW5YvX94tAwAQCgERPE3zDnXv3j3S1QAARDm6zAAAgO8REAEAAN+jywyepkna3nnnHSv36NGDpTsAACEREMHTdLmOffv2uWUAAEIhIIKn6XId9913n1sGACAU7hDwNE3EWKlSpUhXAwAQ5RhUDQAAfI8WInh+6Y6tW7dauXLlyizdAQAIibsDPE2X65gyZYptLN0BADgbWojgabpcR5kyZdwyAAChEBDB0zTvUM+ePSNdDQBAlKPLDAAA+B4BEQAA8D26zOD5pTvef/99K3fp0oWlOwAAIREQwdN0uY5du3a5ZQAAQiEggqfpch0dOnRwywAAhMIdAp6miRirVq0a6WoAAKIcg6oBAIDv0UIEzy/dsXPnTiuXK1eOpTsAACFxd4Cn6XIdkyZNso2lOwAAZ0MLETxNl+soXry4WwYAIBQCInia5h16+OGHI10NAECUo8sMAAD4HgERAADwPbrM4PmlOz766CMrd+zYkaU7AAAhERDB03S5jm3btrllAABCISCCp+lyHe3atXPLAACEwh0CnqaJGGvVqhXpagAAolzEB1X/97//lfvuu0+KFi0qefPmlZo1a8qqVavc/drNMXz4cCldurTtb9mypWzZsiXFOQ4cOCCdO3eWggULSuHChaVHjx5y5MiRFMesW7dOmjZtKnny5JGyZcvKmDFjMu1nBAAA0S2iAdGff/4pjRs3toGuX331lWzatElefPFFufTSS91jNHD517/+JePHj5fly5dL/vz5JTY2VpKSktxjNBjauHGjzJ07V2bOnCnffPONPPTQQ+7+xMREadWqlZQvX15Wr14tzz//vDz99NPy1ltvZfrPjMxfukODbt20DABAKDGBCI40HTp0qCxZskS+/fbbkPu1amXKlJEBAwbIwIED7bVDhw5JyZIlZeLEiTZr6KeffpLq1avLypUrpV69enbM7Nmz5ZZbbpHdu3fb17/xxhvy+OOPy969eyVXrlzu954xY4Zs3rz5jO97/Phx24IDKm1V0u+trVDRqsLQWec9ZsfoNuInJ06ckFGjRll52LBh7u8fAOB9iYmJUqhQoTTdvyPaQvT5559bEHP33XdLiRIl5Nprr5V///vf7v7t27dbEKPdZA79wRo0aCBLly615/qo3WROMKT0eB07oi1KzjHNmjVLcTPUVqb4+HhrpUpNb6D6fZxNgyFkTbpch/N7ZOkOAEBUBkQ6HVpbb6688kqZM2eO9O7dWx599FFbiFNpMKS0RSiYPnf26aMGU8F0NlGRIkVSHBPqHMHfI5i2JGg06Wy7du0K68+NzKPdsf369bONHEQAgKicZaZjOrRl55///Kc91xaiDRs22Hihbt26RaxeuXPntg0AAPhDRFuIdOaYjv8JVq1aNdm5c6eVS5UqZY/79u1LcYw+d/bpY0JCQor9J0+etJlnwceEOkfw9wAAAP4V0YBIZ5jpOJ5gP//8s80GUxUrVrSAZf78+SkGSOnYoEaNGtlzfTx48KDNHnMsWLDAWp90rJFzjM4802UcHDojrUqVKilmtMF7NDjWpTt00zIAAFEXEPXv31+WLVtmXWZbt26VDz/80KbC9+nTx/brIFgd+/Hss8/aAOz169dL165dbeZY27Zt3Ral1q1bS8+ePWXFihU2a61v3742A02PU506dbIB1ZqfSKfnf/zxxzJ27FiJi4uL5I+PTKCBsQbdujHtHgAQlWOI6tevL9OnT7dBzCNHjrQWoVdeecXyCjkGDx4sf/31l+UV0pagJk2a2LR6TbDomDx5sgVBLVq0sNll7du3t9xFDp1h9PXXX1ugVbduXSlWrJglewzOVQRvyp49u9x6661uGQCAqMtD5MU8BpFEHiIAALJgHiIAAIBowOKu8DRtAN2/f7+VixcvTnJGAEBItBDB03RmoSb/1C14liEAAMFoIYLn5cuXL9JVAABEOQIieJqmWxg0aFCkqwEAiHJ0mQEAAN8jIAIAAL5Hlxk8TZfr0Czn6vbbb5ccOXjLAwDORAsRPE2X69AlX3Rj6Q4AwNnwcRmepst1xMbGumUAAEIhIIKnaRDUsGHDSFcDABDl6DIDAAC+RwsRPL90hy7qp3SBP5buAACEQgsRPE2X6xg7dqxtLN0BADgbWojgeTlz5ox0FQAAUY6ACJ5fuuMf//hHpKsBAIhydJkBAADfIyACAAC+R5cZPL90x5dffmnlW265haU7AAAh0UIET9PlOn788UfbWLoDAHA2fFyG5zNVN2/e3C0DABAKARE8TYOgZs2aRboaAIAoR5cZAADwPVqI4PmlO44ePWrlfPnysXQHACAkWojgabpcxwsvvGAbS3cAAM6GgAgAAPgeXWbw/NIdTz31VKSrAQCIcrQQAQAA3yMgAgAAvkeXGTy/dMe8efOs3LJlS5buAACERAsRPE2X61i+fLltLN0BADgbPi7D85mqmzRp4pYBAAiFgAiepkFQixYtIl0NAECUo8sMAAD4Hi1E8PzSHU6G6pw5c7J0BwAgJFqI4GkaDI0aNco2lu4AAJwNAREAAPA9uszgadpNNmzYMLcMAEDUtRA9/fTTNqYjeKtataq7PykpSfr06SNFixaVAgUKSPv27WXfvn0pzrFz505p06aN5MuXT0qUKCGDBg2yZHzBFi1aJHXq1JHcuXNL5cqVZeLEiZn2MyKy9D2l65npxvghAEDUdpldffXVsmfPHnf77rvv3H39+/eXL774QqZNmyaLFy+W3377Te688053/6lTpywYOnHihHz//fcyadIkC3aGDx/uHrN9+3Y7pnnz5rJmzRrp16+fPPjggzJnzpxM/1kBAEB0iniXmS6lUKpUqTNeP3TokLzzzjvy4Ycfyk033WSvTZgwQapVqybLli2Thg0bytdffy2bNm2ypRlKliwptWvXlmeeeUaGDBlirU/aKjB+/HipWLGivPjii3YO/XoNul5++WWJjY3N9J8XmUuDZm0hVDfeeCPJGQEA0dlCtGXLFilTpoxcccUV0rlzZ+sCU6tXr7ZZQbr+lEO708qVKydLly615/pYs2ZNC4YcGuQkJibKxo0b3WOCz+Ec45wjlOPHj9s5gjdk3YBIA2DdtAwAQNQFRA0aNLAurtmzZ8sbb7xh3VtNmzaVw4cPy969e62Fp3Dhwim+RoMf3af0MTgYcvY7+851jAY5x44dC1kvnaJdqFAhdytbtmxYf25knmzZstn7TDctAwAQdV1mN998s1uuVauW3bTKly8vU6dOlbx580as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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 35
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## Tokenizer",
   "id": "5b9c3c5072d49c29"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.809300Z",
     "start_time": "2025-01-23T12:00:10.792786Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500,\n",
    "                 pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx  # 词典，单词->id\n",
    "        self.idx2word = idx2word  # 反向词典，id->单词\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx  #填充\n",
    "        self.bos_idx = bos_idx  #开始\n",
    "        self.eos_idx = eos_idx  #结束\n",
    "        self.unk_idx = unk_idx  #未知，未出现在最高频词表中的词\n",
    "\n",
    "    def encode(self, test_list):\n",
    "        \"\"\"\n",
    "        将文本列表转化为索引列表\n",
    "        :param test_list: 当前批次的文本列表\n",
    "        \"\"\"\n",
    "        # 最大长度，最大长度是500，\n",
    "        # 但是如果句子长度小于500，就取句子长度（句子长度是本组句子中最长的），\n",
    "        # 2是为了留出开始和结束的位置\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in test_list]))\n",
    "        indices = []\n",
    "        for text in test_list:\n",
    "            # 单词转化为id，未知的词用unk_idx代替\n",
    "            index = [self.word2idx.get(word, self.unk_idx) for word in text]\n",
    "            # 添加开始和结束\n",
    "            index = [self.bos_idx] + index + [self.eos_idx]\n",
    "            if len(index) < max_length:\n",
    "                index = index + [self.pad_idx] * (max_length - len(index))  #填充0\n",
    "            else:\n",
    "                index = index[:max_length]  # 如果句子长度大于500，就截断\n",
    "            indices.append(index)\n",
    "        return torch.tensor(indices)  # 二维列表转化为tensor\n",
    "\n",
    "    def decode(self, indices_list, remove_bos=True,\n",
    "               remove_eos=True, remove_pad=True, split=False):\n",
    "        \"\"\"\n",
    "        将索引列表转化为文本列表\n",
    "        \"\"\"\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\": continue\n",
    "                if remove_eos and word == \"[EOS]\": break\n",
    "                if remove_pad and word == \"[PAD]\": break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "\n",
    "\n",
    "tokenizer = Tokenizer(word2idx, idx2word, max_length=MAX_LENGTH)"
   ],
   "id": "b58b84ec603ebc7",
   "outputs": [],
   "execution_count": 36
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.815481Z",
     "start_time": "2025-01-23T12:00:10.810297Z"
    }
   },
   "cell_type": "code",
   "source": [
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text)  # encode支持批量处理\n",
    "print(\"raw text\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\")\n",
    "for index in indices:\n",
    "    print(index)"
   ],
   "id": "5236f40c64a5a202",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices\n",
      "tensor([   1, 4825,  182,    3,    0,    0,    0])\n",
      "tensor([    1,     2,  3004,     2,    19, 19233,     3])\n",
      "tensor([   1,   14,    9,    6, 2181,    3,    0])\n"
     ]
    }
   ],
   "execution_count": 37
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.820519Z",
     "start_time": "2025-01-23T12:00:10.816478Z"
    }
   },
   "cell_type": "code",
   "source": [
    "decoded_text = tokenizer.decode(indices.tolist(),\n",
    "                                remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"decode text----------\")\n",
    "for decode in decoded_text:\n",
    "    print(decode)"
   ],
   "id": "2552a3d90c4ccc3d",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "decode text----------\n",
      "[BOS] hello world [EOS] [PAD] [PAD] [PAD]\n",
      "[BOS] [UNK] text [UNK] with batch [EOS]\n",
      "[BOS] this is a test [EOS] [PAD]\n"
     ]
    }
   ],
   "execution_count": 38
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:10.825943Z",
     "start_time": "2025-01-23T12:00:10.821516Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 看看训练集的数据\n",
    "tokenizer.decode(train_data[0:1],\n",
    "                 remove_bos=False, remove_eos=False, remove_pad=False)"
   ],
   "id": "67e228f59f9798c7",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[\"[BOS] this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert [UNK] is an amazing actor and now the same being director [UNK] father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for [UNK] and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also [UNK] to the two little boy's that played the [UNK] of norman and paul they were just brilliant children are often left out of the [UNK] list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all\"]"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 39
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 数据集与DataLoader",
   "id": "4c5986d8827d9b25"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:12.330422Z",
     "start_time": "2025-01-23T12:00:10.826934Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, data, labels, remain_length=True):\n",
    "        if remain_length:  # 打印【BOS】，【EOS】，【PAD】\n",
    "            self.data = tokenizer.decode(data, remove_bos=False,\n",
    "                                         remove_eos=False, remove_pad=False)\n",
    "        else:  # 不能打印【BOS】，【EOS】，【PAD】\n",
    "            self.data = tokenizer.decode(data)\n",
    "        self.labels = labels\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        text = self.data[index]\n",
    "        label = self.labels[index]\n",
    "        return text, label\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.data)\n",
    "\n",
    "\n",
    "def collate_fct(batch):\n",
    "    \"\"\"\n",
    "    将batch数据处理成tensor形式\n",
    "    \"\"\"\n",
    "    # batch是128样本，每个样本类型是元组，第一个元素是文本，第二个元素是标签\n",
    "    text_list = [item[0].split() for item in batch]\n",
    "    label_list = [item[1] for item in batch]\n",
    "    # 文本转化为索引\n",
    "    text_list = tokenizer.encode(text_list).to(dtype=torch.int)\n",
    "    # torch.tensor(label_list):将 Python 列表 label_list 转换为 PyTorch 张量。\n",
    "    # .reshape(-1, 1):将张量的形状重塑为 (n, 1)，其中 n 是 label_list 的长度。\n",
    "    # .to(dtype=torch.float):将张量的数据类型转换为 float。\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "\n",
    "train_ds = IMDBDataset(train_data, train_labels)\n",
    "test_ds = IMDBDataset(test_data, test_labels)\n",
    "\n",
    "batch_size = 128\n",
    "# collate_fn是处理batch的函数\n",
    "train_loader = DataLoader(train_ds, batch_size=batch_size,\n",
    "                          shuffle=True, collate_fn=collate_fct)\n",
    "test_loader = DataLoader(test_ds, batch_size=batch_size,\n",
    "                         shuffle=False, collate_fn=collate_fct)"
   ],
   "id": "73712533465907cc",
   "outputs": [],
   "execution_count": 40
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.206462Z",
     "start_time": "2025-01-23T12:00:12.331420Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#要看到每个batch的长度不同，需要修改batch_size为12\n",
    "i = 0\n",
    "for text, label in train_loader:\n",
    "    print(text.shape, label.shape)\n",
    "    i += 1\n",
    "    if i == 50:\n",
    "        break"
   ],
   "id": "13760ef0c4c91058",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n",
      "torch.Size([128, 500]) torch.Size([128, 1])\n"
     ]
    }
   ],
   "execution_count": 41
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 定义模型",
   "id": "7001311e460c0b99"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.213054Z",
     "start_time": "2025-01-23T12:00:13.207512Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class AddingModel(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size):\n",
    "        super(AddingModel, self).__init__()\n",
    "        # 词嵌入层\n",
    "        # 生成一万个one-hot编码，将其映射到16维空间\n",
    "        self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.pool = nn.AdaptiveAvgPool1d(1)  # 全局平均池化\n",
    "        self.layer = nn.Linear(embedding_dim, hidden_dim)  # 全连接层\n",
    "        self.fc = nn.Linear(hidden_dim, 1)  # 输出层\n",
    "\n",
    "    def forward(self, x):\n",
    "        # [bacth_size,seq_len,vocab_size]->[batch_size,seq_len,embedding_dim]\n",
    "        # [batch_size, 500,10000]->[batch_size, 500,16]\n",
    "        x = self.embedding(x)  # 词嵌入\n",
    "        # [batch_size,seq_len,embedding_dim]->[batch_size,embedding_dim,seq_len]\n",
    "        # [batch_size, 500,16]->[batch_size, 16,500]\n",
    "        x = x.permute(0, 2, 1)  # 转置\n",
    "        # [batch_size,embedding_dim,seq_len]->[batch_size,embedding_dim,1]\n",
    "        # [batch_size, 16,500]->[batch_size, 16,1]\n",
    "        x = self.pool(x)  # 全局平均池化\n",
    "        # [batch_size,embedding_dim,1]->[batch_size,embedding_dim]\n",
    "        # [batch_size, 16,1]->[batch_size, 16]\n",
    "        x = x.squeeze(2)  # 去掉最后一维\n",
    "        # [batch_size,embedding_dim]->[batch_size,hidden_dim]\n",
    "        # [batch_size, 16]->[batch_size, 64]\n",
    "        x = self.layer(x)  # 全连接层\n",
    "        # [batch_size,hidden_dim]->[batch_size,1]\n",
    "        # [batch_size, 64]->[batch_size, 1]\n",
    "        x = self.fc(x)  # 输出层\n",
    "        return x"
   ],
   "id": "22ab9152ea499fd4",
   "outputs": [],
   "execution_count": 42
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.220826Z",
     "start_time": "2025-01-23T12:00:13.214050Z"
    }
   },
   "cell_type": "code",
   "source": [
    "for key, value in AddingModel().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ],
   "id": "806fc209f7870230",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "            embedding.weight            paramerters num: 160000\n",
      "              layer.weight              paramerters num: 1024\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "execution_count": 43
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 训练模型",
   "id": "9ef16b2489a34e67"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.227335Z",
     "start_time": "2025-01-23T12:00:13.221823Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()  # 装饰器，禁止梯度计算\n",
    "def evaluate(model, data_loader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in data_loader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "\n",
    "        # 前向传播\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        # tensor.item() 获取tensor的数值，loss是只有一个元素的tensor\n",
    "        loss_list.append(loss.item())\n",
    "\n",
    "        # 二分类\n",
    "        preds = logits > 0  # 预测值大于0的为1，否则为0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())  \n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)  # 计算准确率\n",
    "    return np.mean(loss_list), acc  # # 返回验证集平均损失和准确率"
   ],
   "id": "ff68a430988cfb82",
   "outputs": [],
   "execution_count": 44
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.235715Z",
     "start_time": "2025-01-23T12:00:13.228372Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=500, save_best_only=True):\n",
    "        self.save_dir = save_dir  # 保存路径\n",
    "        self.save_step = save_step  # 保存步数\n",
    "        self.save_best_only = save_best_only  # 是否只保存最好的模型\n",
    "        self.best_metric = -1  # 最好的指标，指标不可能为负数，所以初始化为-1\n",
    "        # 创建保存路径\n",
    "        if not os.path.exists(self.save_dir):  # 如果不存在保存路径，则创建\n",
    "            os.makedirs(self.save_dir)\n",
    "\n",
    "    # 对象被调用时：当你将对象像函数一样调用时，Python 会自动调用 __call__ 方法。\n",
    "    # state_dict() 返回模型参数的字典，包括模型参数和优化器参数\n",
    "    # metric 是指标，可以是验证集的准确率，也可以是其他指标\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return  # 不是保存步数，则直接返回\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None  # 必须传入metric\n",
    "            if metric >= self.best_metric:  # 如果当前指标大于最好的指标\n",
    "                # save checkpoint\n",
    "                # 保存最好的模型，覆盖之前的模型，不保存step，只保存state_dict，即模型参数，不保存优化器参数\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"01_embedding_padding_pooling.ckpt\"))\n",
    "                self.best_metric = metric  # 更新最好的指标\n",
    "        else:\n",
    "            # 保存模型\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "            # 保存每个step的模型，不覆盖之前的模型，保存step，保存state_dict，即模型参数，不保存优化器参数\n"
   ],
   "id": "8c4b85e148a60f34",
   "outputs": [],
   "execution_count": 45
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.242143Z",
     "start_time": "2025-01-23T12:00:13.237676Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        self.patience = patience  # 多少个step没有提升就停止训练\n",
    "        self.min_delta = min_delta  # 最小的提升幅度\n",
    "        self.best_metric = -1  # 记录的最好的指标\n",
    "        self.counter = 0  # 计数器，记录连续多少个step没有提升\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:  # 如果指标提升了\n",
    "            self.best_metric = metric  # 更新最好的指标\n",
    "            self.counter = 0  # 计数器清零\n",
    "        else:\n",
    "            self.counter += 1  # 计数器加一\n",
    "\n",
    "    @property  # 使用@property装饰器，使得 对象.early_stop可以调用，不需要()\n",
    "    def early_stop(self):\n",
    "        # 如果计数器大于等于patience，则返回True，停止训练\n",
    "        return self.counter >= self.patience"
   ],
   "id": "a3f65b1f7f9b4dff",
   "outputs": [],
   "execution_count": 46
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:13.252737Z",
     "start_time": "2025-01-23T12:00:13.243136Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def training(model,\n",
    "             train_loader,\n",
    "             val_loader,\n",
    "             epoch,\n",
    "             loss_fct,\n",
    "             optimizer,\n",
    "             save_ckpt_callback=None,\n",
    "             early_stop_callback=None,\n",
    "             eval_step=500,\n",
    "             ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0  # 全局步数\n",
    "    model.train()  # 训练模式\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "\n",
    "                # 前向传播\n",
    "                logits = model(datas)\n",
    "                loss = loss_fct(logits, labels)  # 训练集损失\n",
    "                #当sigmoid输出大于0.5时，预测为1，否则预测为0，这里大于0，刚好sigmoid的值是0.5，预测为1\n",
    "                preds = logits > 0\n",
    "\n",
    "                # 反向传播\n",
    "                optimizer.zero_grad()  # 梯度清零\n",
    "                loss.backward()  # 反向传播\n",
    "                optimizer.step()  # 优化器更新参数\n",
    "\n",
    "                # 计算准确率\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
    "                loss = loss.cpu().item()\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss,\n",
    "                    \"acc\": acc,\n",
    "                    \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # 评估\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()  # 评估模式\n",
    "                    # 验证集损失和准确率\n",
    "                    val_loss, val_acc = evaluate(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss,\n",
    "                        \"acc\": val_acc,\n",
    "                        \"step\": global_step\n",
    "                    })\n",
    "                    model.train()  # 训练模式\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        # model.state_dict() 返回模型参数的字典，包括模型参数和优化器参数\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), val_acc)\n",
    "                        # 保存最好的模型，覆盖之前的模型，保存step，保存state_dict,通过metric判断是否保存最好的模型\n",
    "\n",
    "                    # 3. 早停 early stopping\n",
    "                    if early_stop_callback is not None:\n",
    "                        # 验证集准确率不再提升，则停止训练\n",
    "                        early_stop_callback(val_acc)\n",
    "                        # 验证集准确率不再提升，则停止训练\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict  # 早停，返回记录字典 record_dict\n",
    "\n",
    "                # 更新进度条和全局步数\n",
    "                pbar.update(1)  # 更新进度条\n",
    "                global_step += 1  # 全局步数加一\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict  # 训练结束，返回记录字典 record_dict\n"
   ],
   "id": "9d1b64287652db63",
   "outputs": [],
   "execution_count": 47
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:00:15.087581Z",
     "start_time": "2025-01-23T12:00:13.253732Z"
    }
   },
   "cell_type": "code",
   "source": [
    "epoch = 100\n",
    "\n",
    "model = AddingModel()\n",
    "model.to(device)\n",
    "\n",
    "# 1. 定义损失函数 采用二进制交叉熵损失, 先sigmoid再计算交叉熵\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 等价于 loss_fct =nn.BCEWithLogitsLoss()\n",
    "\n",
    "# 2. 定义优化器\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 3.save model checkpoint\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(save_dir=\"checkpoints\", save_step=len(train_loader), save_best_only=True)\n",
    "\n",
    "# 4. early stopping\n",
    "early_stop_callback = EarlyStopCallback(patience=5, min_delta=0.01)"
   ],
   "id": "eb47aada8173cbab",
   "outputs": [],
   "execution_count": 48
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:02:33.837907Z",
     "start_time": "2025-01-23T12:00:15.088577Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 训练过程\n",
    "record_dict = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    test_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_loader)\n",
    ")"
   ],
   "id": "808140ac71443826",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/19600 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "506ac81d9506453b997455fe482be610"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 15 / global_step 2940\n"
     ]
    }
   ],
   "execution_count": 49
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:08:35.589640Z",
     "start_time": "2025-01-23T12:08:35.436048Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def plot_record_curves(record_dict, sample_step=500):\n",
    "    # .set_index(\"step\") 将 step 列设置为 DataFrame 的索引\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    last_step = train_df.index[-1]  # 最后一步的步数\n",
    "\n",
    "    # print(train_df)\n",
    "    # print(val_df)\n",
    "\n",
    "    # 画图 \n",
    "    fig_num = len(train_df.columns)  # 画两张图,分别是损失和准确率\n",
    "\n",
    "    # plt.subplots：用于创建一个包含多个子图的图形窗口。\n",
    "    # 1：表示子图的行数为 1。\n",
    "    # fig_num：表示子图的列数，即子图的数量。\n",
    "    # figsize=(5 * fig_num, 5)：设置整个图形窗口的大小，宽度为 5 * fig_num，高度为 5。\n",
    "    # fig：返回的图形对象（Figure），用于操作整个图形窗口。\n",
    "    # axs：返回的子图对象（Axes 或 Axes 数组），用于操作每个子图。\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        # train_df.index 是 x 轴数据（通常是 step）。\n",
    "        # train_df[item] 是 y 轴数据（当前指标的值）。\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=\"train:\" + item)\n",
    "        # val_df.index 是 x 轴数据。\n",
    "        # val_df[item] 是 y 轴数据。\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=\"val:\" + item)\n",
    "        axs[idx].grid()  # 显示网格\n",
    "        axs[idx].legend()  # 显示图例\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1] + 1, 5000))  # 设置x轴刻度\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{x // 1000}k\", range(0, last_step + 1, 5000)))  # 设置x轴标签\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_record_curves(record_dict)"
   ],
   "id": "a5ca845ce9dfae24",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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/i0bqtGhjcfOwtfNiMcHtcKYXk1Qz4NfL0SV2XuqeCHVCM4PIiKyFh6pENE1iQzURof2nDyHIzvWY1SfaLi58auF6GqmjGyNyKIzGN4+xNpNISJyWM41edLMmTMRHR0NT09P9OjRA1u3bq102zlz5uC6665D/fr11WXw4MFX3Z6I7I+zsxPahfvBXTLjiKhKDXw80K6+EVGB3tZuChGRw6p2ILRgwQJMmjQJU6ZMwc6dOxEbG4thw4YhNTW1wu1Xr16Nu+++G6tWrcKmTZsQGRmJoUOH4vTp07XRfiIiIiIioroPhGbMmIEJEyZg/PjxaNu2LWbPng1vb2/MnTu3wu2/+uorPPbYY+jYsSNat26NTz75BAaDAStWrKh+a4mIiIiIiCwdCOXn52PHjh0qva3kP3B2VrdltMccOTk5KCgoQGBgYPVbS0REREREVAuqNaM5PT0dRUVFCAkpO7lTbh86dMis/+O5555DeHh4mWCqvLy8PHUxycjQqutIACWX6jI9pybPtWV67Zee+6bXfum5b3rtl7l902O/iYiIhEVLO/3nP//Bt99+q+YNSaGFykybNg1Tp0694v5ly5apNLyaWr58OfRIr/3Sc9/02i89902v/aqqbzKKT0REBEcPhIKCguDi4oKUlJQy98vt0NDQqz737bffVoHQn3/+iZiYmKtu+8ILL6iCDKVHhExFFvz8qr/4nJzRlB39kCFD4Oamn8Ud9dovPfdNr/3Sc9/02i9z+2YakSciInLoQMjd3R1dunRRhQ5GjRql7jMVPpg4cWKlz3vrrbfw+uuvY+nSpejatWuVv8fDw0NdypMd9bUciFzr822VXvul577ptV967pte+1VV3/TaZyIiomqnxslIzbhx41RA0717d7z77rvIzs5WVeTE2LFjERERodLbxJtvvonJkyfj66+/VmsPJScnq/t9fHzUhYiIiIiIyOYDodGjRyMtLU0FNxLUSFnsJUuWlBRQSExMVJXkTGbNmqWqzd1xxx1l/h9Zh+iVV16pjT4QERERERHVfbEESYOrLBVOCiGUlpCQUJNfQUREREREZDsLqhIREREREdk7BkJERERERORwGAgREREREZHDYSBEREREREQOp0bFEizNaDRe08J+smigrI4uz9fTmhh67Zee+6bXfum5b3rtl7l9M33vmr6HScP9kuP1Ta/90nPf9NovPfetwMx+1da+yS4CoczMTPUzMjLS2k0hInJI8j3s7+9v7WbYDO6XiIjsf9/kZLSD03wGgwFnzpyBr68vnJycqv18iRplZ3Xy5En4+flBL/TaLz33Ta/90nPf9Novc/smuwjZ0YSHh5dZI87Rcb/keH3Ta7/03De99kvPfcsws1+1tW+yixEh6WCjRo2u+f+RP6ie3ix675ee+6bXfum5b3rtlzl940jQlbhfcty+6bVfeu6bXvul5775mdGv2tg38fQeERERERE5HAZCRERERETkcBwiEPLw8MCUKVPUTz3Ra7/03De99kvPfdNrv/TeN1un57+9Xvum137puW967Zee++Zh4X7ZRbEEIiIiIiKi2uQQI0JERERERESlMRAiIiIiIiKHw0CIiIiIiIgcDgMhIiIiIiJyOLoPhGbOnIno6Gh4enqiR48e2Lp1K2zZK6+8olYpL31p3bp1yeO5ubl4/PHH0aBBA/j4+OD2229HSkpKmf8jMTERN954I7y9vREcHIxnnnkGhYWFFu/L2rVrcdNNN6lVf6Ufv/zyS5nHpU7H5MmTERYWBi8vLwwePBhHjhwps825c+dw7733qkW1AgIC8OCDDyIrK6vMNnv27MF1112nXmNZjfitt96yar/uv//+K17D4cOH23y/pk2bhm7dusHX11e9b0aNGoW4uLgy29TW+2/16tXo3LmzqgrTvHlzzJs3z+p9GzBgwBWv2yOPPGLTfZs1axZiYmJKFp7r1asX/vjjD7t/vRwB903W2Tfpdb9kTt+4b7Kt7zq97pfsbt9k1LFvv/3W6O7ubpw7d65x//79xgkTJhgDAgKMKSkpRls1ZcoUY7t27YxJSUkll7S0tJLHH3nkEWNkZKRxxYoVxu3btxt79uxp7N27d8njhYWFxvbt2xsHDx5s/Ouvv4yLFy82BgUFGV944QWL90V+90svvWT86aefpDKh8eeffy7z+H/+8x+jv7+/8ZdffjHu3r3bePPNNxubNGlivHTpUsk2w4cPN8bGxho3b95sXLdunbF58+bGu+++u+TxixcvGkNCQoz33nuvcd++fcZvvvnG6OXlZfzoo4+s1q9x48apdpd+Dc+dO1dmG1vs17Bhw4yfffaZ+n27du0y3nDDDcbGjRsbs7KyavX9d/z4caO3t7dx0qRJxgMHDhjff/99o4uLi3HJkiVW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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 52
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 评估",
   "id": "5e7f0ed7eeeb25be"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T12:02:37.431416Z",
     "start_time": "2025-01-23T12:02:33.975951Z"
    }
   },
   "cell_type": "code",
   "source": [
    "model.load_state_dict(torch.load(\"checkpoints/01_embedding_padding_pooling.ckpt\", weights_only=True, map_location=device))  # 加载最好的模型\n",
    "\n",
    "model.eval()  # 评估模式\n",
    "loss, acc = evaluate(model, test_loader, loss_fct)\n",
    "print(f\"Test loss: {loss:.4f}, Test acc: {acc:.4f}\")"
   ],
   "id": "a05cb7b998fdae90",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test loss: 0.3122, Test acc: 0.8802\n"
     ]
    }
   ],
   "execution_count": 51
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
